#include <QFileDialog>
#include <QScrollBar>
#include <QPainter>
#include <QList>

#include "window/ImagesManager.hpp"

ImagesManager::ImagesManager(QScrollArea* parent){
    this->setFixedSize(1, 1);
    this->setMouseTracking(true);

    this->parent = parent;

    this->hoverIndex = 0;

    this->mouseHoding = false;
    this->draging = false;

    this->showingIndex = 0;

    this->scale = 1;

    this->contextMenu = new QMenu(this);

    this->viewImageAction        = new QAction("查看图像", this);

    this->addImagesAction        = new QAction("添加图像", this);
    this->removeImagesAction     = new QAction("移除图像", this);

    this->insertAtPreviousAction = new QAction("向前插入", this);
    this->insertAtNextAction     = new QAction("向后插入", this);

    this->clearImagesAction      = new QAction("清空图像", this);

    this->contextMenu->addAction(this->viewImageAction);
    this->contextMenu->addSeparator();
    this->contextMenu->addAction(this->addImagesAction);
    this->contextMenu->addAction(this->removeImagesAction);
    this->contextMenu->addSeparator();
    this->contextMenu->addAction(this->insertAtPreviousAction);
    this->contextMenu->addAction(this->insertAtNextAction);
    this->contextMenu->addSeparator();
    this->contextMenu->addAction(this->clearImagesAction);

    QObject::connect(this->viewImageAction, SIGNAL(triggered()), this, SLOT(viewImage()));
    QObject::connect(this->addImagesAction, SIGNAL(triggered()), this, SLOT(addImages()));
    QObject::connect(this->removeImagesAction, SIGNAL(triggered()), this, SLOT(removeImages()));
    QObject::connect(this->clearImagesAction, SIGNAL(triggered()), this, SLOT(clearImages()));
    QObject::connect(this->insertAtPreviousAction, SIGNAL(triggered()), this, SLOT(insertAtPrevious()));
    QObject::connect(this->insertAtNextAction, SIGNAL(triggered()), this, SLOT(insertAtNext()));

    this->parent->viewport()->installEventFilter(this);

}

ImagesManager::~ImagesManager(){
    delete addImagesAction;
    delete removeImagesAction;
    delete clearImagesAction;
    delete insertAtPreviousAction;
    delete insertAtNextAction;

    delete contextMenu;
    
}

void ImagesManager::paintEvent(QPaintEvent*){
    QPainter p = QPainter(this);

    // 计算图像尺寸
    const float IMAGE_SIZE  = (float)(this->parentWidget()->width() - this->SPACE_SIZE * (this->ROW_SIZE + 1)) / this->ROW_SIZE;

    // 调整控件尺寸
    if(this->images.size() != 0){
        int height;
        if(this->images.size() % this->ROW_SIZE == 0){
            height = (IMAGE_SIZE + this->INDEX_SIZE) * (this->images.size() / this->ROW_SIZE) + this->SPACE_SIZE * (this->images.size() / this->ROW_SIZE + 1);

        }else{
            height = (IMAGE_SIZE + this->INDEX_SIZE) * (this->images.size() / this->ROW_SIZE + 1) + this->SPACE_SIZE * (this->images.size() / this->ROW_SIZE + 2);

        }

        if(height < this->parentWidget()->height()){
            this->setMinimumSize(this->parentWidget()->width(), this->parentWidget()->height());

        }else{
            this->setMinimumSize(this->parentWidget()->width(), height);

        }

    }else{
        this->setMinimumSize(this->parentWidget()->width(), this->parentWidget()->height());

    }

    // 计算矩形区域
    this->rects.clear();

    for(int i = 0; i < this->images.size(); i++){
        this->rects.push_back(QRect((IMAGE_SIZE + this->SPACE_SIZE) * (i % this->ROW_SIZE) + this->SPACE_SIZE, (IMAGE_SIZE + this->SPACE_SIZE + this->INDEX_SIZE) * (i / this->ROW_SIZE) + this->SPACE_SIZE, IMAGE_SIZE, IMAGE_SIZE + this->INDEX_SIZE));

    }

    // 绘制图片
    if(this->images.size() != 0){
        for(int i = 0; i < this->images.size(); i++){
            Image data = this->images.at(i);
            QImage image = data.getImage();

            float imageWidth;
            float imageHeight;

            // 图像缩放
            if(1 > (float)image.width() / image.height()){
                imageWidth  = IMAGE_SIZE / image.height() * image.width();
                imageHeight = IMAGE_SIZE;

            }else{
                imageWidth  = IMAGE_SIZE;
                imageHeight = IMAGE_SIZE / image.width() * image.height();

            }

            p.setBrush(QBrush(QColor(0, 0, 0, 0)));
            p.setPen(QPen(QColor(0, 0, 0)));

            p.drawImage(this->rects.at(i).x() + (IMAGE_SIZE - imageWidth) / 2, this->rects.at(i).y() + (IMAGE_SIZE - imageHeight) / 2, image.scaled(imageWidth, imageHeight, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
            p.drawText(QRect(this->rects.at(i).x(), this->rects.at(i).y() + IMAGE_SIZE, IMAGE_SIZE, this->INDEX_SIZE), Qt::AlignCenter, QString("%1").arg(i + 1));

        }

        if(this->hoverIndex != 0 && !this->focusList.contains(this->hoverIndex)){
            p.setBrush(QBrush(QColor(0, 0, 0, 255 * 0.0625)));
            p.setPen(QPen(QColor(0, 0, 0, 0)));

            p.drawRoundedRect(this->rects.at(this->hoverIndex - 1), 15, 15);

        }

        if(this->focusList.size() != 0){
            p.setBrush(QBrush(QColor(0, 0, 0, 255 * 0.125)));
            p.setPen(QPen(QColor(0, 0, 0, 0)));

            for(Byte i: this->focusList){
                p.drawRoundedRect(this->rects.at(i - 1), 15, 15);

            }

        }

    }

    if(this->mouseHoding){
        p.setBrush(QBrush(QColor(0, 0, 0, 255 * 0.125)));
        p.setPen(QPen(QColor(0, 0, 0, 0)));

        p.drawRect(this->mousePressX, this->mousePressY, this->mouseMoveX - this->mousePressX, this->mouseMoveY - this->mousePressY);

    }

    // 绘制显示的图像
    if(this->showingIndex != 0){
        // 控件宽高
        float widgetWidth  = this->parentWidget()->width();
        float widgetHeight = this->parentWidget()->height();

        Image data = this->images.at(this->showingIndex - 1);

        // 图像缩放
        if(widgetWidth / widgetHeight > (float)data.getImage().width() / data.getImage().height()){
            this->imageWidth  = widgetHeight / data.getImage().height() * data.getImage().width() * this->scale;
            this->imageHeight = widgetHeight * this->scale;

        }else{
            this->imageWidth  = widgetWidth * this->scale;
            this->imageHeight = widgetWidth / data.getImage().width() * data.getImage().height() * this->scale;

        }

        // 坐标运算
        this->imageX = widgetWidth / 2 - this->viewX * (this->imageWidth / data.getImage().width());
        this->imageY = widgetHeight / 2 - this->viewY * (this->imageHeight / data.getImage().height());

        p.setBrush(QBrush(QColor(0, 0, 0, 255 * 0.25)));
        p.setPen(QPen(QColor(0, 0, 0, 0)));

        p.drawRect(0, 0, this->width(), this->height());

        // 绘制图像
        p.drawImage(this->imageX, this->imageY + this->parent->verticalScrollBar()->value(), data.getImage().scaled(this->imageWidth, this->imageHeight, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));

    }

    // 绘制缩放倍数
    if(this->scale != 1 && this->showingIndex != 0){
        p.setBrush(QBrush(QColor(0, 0, 0, 0.25 * 255)));
        p.setPen(QPen(QColor(0, 0, 0, 0)));

        p.drawRoundedRect(10 ,10 + this->parent->verticalScrollBar()->value(), 65, 25, 16, 16);

        p.setPen(QPen(QColor(255, 255, 255)));
        p.drawText(10, 10 + this->parent->verticalScrollBar()->value(), 65, 25, Qt::AlignCenter, QString("x%1").arg(this->scale, 0, 'f', 2));

    }

}

void ImagesManager::mousePressEvent(QMouseEvent* event){
    QPoint pos = event->pos();

    if(event->button() == Qt::LeftButton){
        if(this->showingIndex == 0){
            if(event->modifiers() == Qt::ControlModifier){
                const float IMAGE_SIZE  = (float)(this->parentWidget()->width() - this->SPACE_SIZE * (this->ROW_SIZE + 1)) / this->ROW_SIZE;

                for(int i = 0; i < this->images.size(); i++){
                    QRect rect((IMAGE_SIZE + this->SPACE_SIZE) * (i % this->ROW_SIZE) + this->SPACE_SIZE, (IMAGE_SIZE + this->SPACE_SIZE + this->INDEX_SIZE) * (i / this->ROW_SIZE) + this->SPACE_SIZE, IMAGE_SIZE, IMAGE_SIZE + this->INDEX_SIZE);

                    if(rect.contains(event->pos().x(), event->pos().y())){
                        if(this->focusList.contains(i + 1)){
                            this->focusList.removeAt(this->focusList.indexOf(i + 1));

                        }else{
                            this->focusList.push_back(i + 1);

                        }
                        
                    }

                }

                this->update();

            }else if(event->modifiers() == Qt::ShiftModifier && this->focusList.size() != 0){
                const float IMAGE_SIZE  = (float)(this->parentWidget()->width() - this->SPACE_SIZE * (this->ROW_SIZE + 1)) / this->ROW_SIZE;

                Byte index = this->focusList.at(0);
                this->focusList.clear();

                for(int i = 0; i < this->images.size(); i++){
                    QRect rect((IMAGE_SIZE + this->SPACE_SIZE) * (i % this->ROW_SIZE) + this->SPACE_SIZE, (IMAGE_SIZE + this->SPACE_SIZE + this->INDEX_SIZE) * (i / this->ROW_SIZE) + this->SPACE_SIZE, IMAGE_SIZE, IMAGE_SIZE + this->INDEX_SIZE);

                    if(rect.contains(event->pos().x(), event->pos().y())){
                        if(i + 1 - index > 0){
                            for(int j = 0; j < (i + 1) - index + 1; j++){
                                this->focusList.push_back(index + j);

                            }

                        }else if(i + 1 - index < 0){
                            for(int j = 0; j < index - (i + 1) + 1; j++){
                                this->focusList.push_back(index - j);

                            }

                        }else{
                            this->focusList.push_back(index);

                        }
                        
                    }

                }

                this->update();

            }else{
                if(this->inArea(event->pos().x(), event->pos().y()) && this->focusList.size()){
                    this->draging = true;

                }else{
                    const float IMAGE_SIZE  = (float)(this->parentWidget()->width() - this->SPACE_SIZE * (this->ROW_SIZE + 1)) / this->ROW_SIZE;

                    this->focusList.clear();

                    for(int i = 0; i < this->images.size(); i++){
                        QRect rect((IMAGE_SIZE + this->SPACE_SIZE) * (i % this->ROW_SIZE) + this->SPACE_SIZE, (IMAGE_SIZE + this->SPACE_SIZE + this->INDEX_SIZE) * (i / this->ROW_SIZE) + this->SPACE_SIZE, IMAGE_SIZE, IMAGE_SIZE + this->INDEX_SIZE);

                        if(rect.contains(event->pos().x(), event->pos().y())){
                            this->focusList.push_back(i + 1);
                            
                        }

                    }

                    this->mouseHoding = true;

                    this->mousePressX = event->pos().x();
                    this->mousePressY = event->pos().y();

                    this->mouseMoveX = event->pos().x();
                    this->mouseMoveY = event->pos().y();

                    this->update();

                }

            }

        }else{
            QRect rect(this->imageX, this->imageY + this->parent->verticalScrollBar()->value(), this->imageWidth, this->imageHeight);

            if(!rect.contains(event->pos().x(), event->pos().y())){
                this->showingIndex = 0;

                this->update();

            }

        }

    }else if(event->button() == Qt::RightButton){
        if(this->showingIndex != 0){
            QRect rect(this->imageX, this->imageY + this->parent->verticalScrollBar()->value(), this->imageWidth, this->imageHeight);

            if(rect.contains(event->pos().x(), event->pos().y())){
                this->mouseX = pos.x();
                this->mouseY = pos.y();

                this->oldViewX = this->viewX;
                this->oldViewY = this->viewY;

                this->moving = true;

            }

        }

    }else if(event->button() == Qt::MiddleButton){
        this->scale = 1.0;

        Image data = this->images.at(this->showingIndex - 1);

        this->viewX = data.getImage().width() / 2;
        this->viewY = data.getImage().height() / 2;

        this->update();

    }

}

void ImagesManager::mouseReleaseEvent(QMouseEvent*){
    this->mouseHoding = false;
    this->moving = false;

    if(this->draging){
        this->draging = false;

    }

    this->update();

}


void ImagesManager::mouseDoubleClickEvent(QMouseEvent*){
    if(this->images.size() == 0){
        QStringList files = QFileDialog::getOpenFileNames(this, QStringLiteral("添加图片"), "./", QStringLiteral("图片文件(*png *jpg *jpeg)"));

        QList<QImage> images = QList<QImage>();

        // 添加图片
        this->files.append(files);

        for(QString filepath : files){
            this->images.push_back(Image(QImage(filepath)));

        }

        this->update();

    }

}

void ImagesManager::mouseMoveEvent(QMouseEvent* event){
    if(this->showingIndex == 0){
        if(event->buttons() & Qt::LeftButton){
            if(this->draging){
                // 待续
                // 拖拽移动图片顺序的算法实现
                // 别搁那口算了，拿笔吧

            }else if(this->mouseHoding){
                this->mouseMoveX = event->pos().x();
                this->mouseMoveY = event->pos().y();

                // 计算选择矩形
                QRect rect;

                rect.setTop(std::min(this->mousePressY, this->mouseMoveY));
                rect.setBottom(std::max(this->mousePressY, this->mouseMoveY));
                rect.setLeft(std::min(this->mousePressX, this->mouseMoveX));
                rect.setRight(std::max(this->mousePressX, this->mouseMoveX));

                // 清空选择列表
                this->focusList.clear();

                // 选择判断
                for(int i = 0; i < this->rects.size(); i++){
                    if(rect.intersects(this->rects.at(i))){
                        this->focusList.push_back(i + 1);

                    }

                }

                this->update();

            }
            
        }else{
            // 计算图像尺寸
            const float IMAGE_SIZE  = (float)(this->parentWidget()->width() - this->SPACE_SIZE * (this->ROW_SIZE + 1)) / this->ROW_SIZE;

            this->hoverIndex = 0;

            for(int i = 0; i < this->images.size(); i++){
                QRect rect((IMAGE_SIZE + this->SPACE_SIZE) * (i % this->ROW_SIZE) + this->SPACE_SIZE, (IMAGE_SIZE + this->SPACE_SIZE + this->INDEX_SIZE) * (i / this->ROW_SIZE) + this->SPACE_SIZE, IMAGE_SIZE, IMAGE_SIZE + this->INDEX_SIZE);

                if(rect.contains(event->pos().x(), event->pos().y())){
                    this->hoverIndex = i + 1;
                    
                }

            }

            this->update();

        }

    }else if(this->showingIndex != 0 && this->moving){
        Image data = this->images.at(this->showingIndex - 1);

        this->viewX = this->oldViewX - (event->pos().x() - this->mouseX) / (this->imageWidth / data.getImage().width());
        this->viewY = this->oldViewY - (event->pos().y() - this->mouseY) / (this->imageHeight / data.getImage().height());

        if(this->viewX < 0){
            this->viewX = 0;

        }
        
        if(this->viewY < 0){
            this->viewY = 0;

        }

        if(this->viewX > data.getImage().width()){
            this->viewX = data.getImage().width();

        }
        
        if(this->viewY > data.getImage().height()){
            this->viewY = data.getImage().height();

        }

        this->update();

    }

}

void ImagesManager::wheelEvent(QWheelEvent* event){
    if(this->showingIndex != 0){
        if(event->angleDelta().y() > 0){
            if(this->scale < 1 && this->scale * 1.125 > 1){
                this->scale = 1;

            }else{
                this->scale *= 1.125;

                if(this->scale > 10){
                    this->scale = 10;

                }

            }

        }else{
            if(this->scale > 1 && this->scale / 1.125 < 1){
                this->scale = 1;

            }else{
                this->scale /= 1.125;

                if(this->scale < 0.25){
                    this->scale = 0.25;

                }

            }

        }

        this->update();

    }else{
        event->ignore();

    }

}

void ImagesManager::leaveEvent(QEvent*){
    this->hoverIndex = 0;
    this->update();

}

void ImagesManager::contextMenuEvent(QContextMenuEvent* event){
    if(this->showingIndex == 0){
        if(this->inArea(event->pos().x(), event->pos().y())){
            if(this->focusList.size() == 0){
                this->viewImageAction->setDisabled(true);
                this->addImagesAction->setDisabled(false);
                this->removeImagesAction->setDisabled(true);
                this->insertAtPreviousAction->setDisabled(true);
                this->insertAtNextAction->setDisabled(true);
                
                if(this->images.size() == 0){
                    this->clearImagesAction->setDisabled(true);

                }else{
                    this->clearImagesAction->setDisabled(false);

                }

                this->contextMenu->exec(QCursor::pos());
                event->accept();

            }else if(this->focusList.size() == 1){
                this->viewImageAction->setDisabled(false);
                this->addImagesAction->setDisabled(false);
                this->removeImagesAction->setDisabled(false);
                this->insertAtPreviousAction->setDisabled(false);
                this->insertAtNextAction->setDisabled(false);
                this->clearImagesAction->setDisabled(false);

                this->contextMenu->exec(QCursor::pos());
                event->accept();

            }else{
                this->viewImageAction->setDisabled(true);
                this->addImagesAction->setDisabled(false);
                this->removeImagesAction->setDisabled(false);
                this->insertAtPreviousAction->setDisabled(true);
                this->insertAtNextAction->setDisabled(true);
                this->clearImagesAction->setDisabled(false);

                this->contextMenu->exec(QCursor::pos());
                event->accept();

            }

        }else{
            this->focusList.clear();

            this->update();

        }

    }

}

void ImagesManager::resizeEvent(QResizeEvent*){

}

bool ImagesManager::inArea(int x, int y){
    bool inArea = this->focusList.size() == 0 ? true : false;

    for(Byte index : this->focusList){
        QRect rect = this->rects.at(index - 1);

        if(rect.contains(x, y)){
            inArea = true;

            break;

        }


    }

    return inArea;

}

void ImagesManager::viewImage(){
    if(this->focusList.size() == 1){
        this->showingIndex = this->focusList.at(0);
        this->focusList.clear();

        // 缩放
        this->scale = 1.0;

        Image data = this->images.at(this->showingIndex - 1);

        // 计算坐标
        this->viewX = data.getImage().width() / 2;
        this->viewY = data.getImage().height() / 2;

        this->update();

    }

}

void ImagesManager::addImages(){
    QStringList files = QFileDialog::getOpenFileNames(this, QStringLiteral("添加图片"), "./", QStringLiteral("图片文件(*png *jpg *jpeg)"));

    if(files.size() != 0){
        QList<QImage> images = QList<QImage>();

        // 添加图片
        this->files.append(files);

        for(QString filepath : files){
            this->images.push_back(Image(QImage(filepath)));

        }

        this->update();

    }

}

void ImagesManager::removeImages(){
    std::sort(this->focusList.begin(), this->focusList.end());
    std::reverse(this->focusList.begin(), this->focusList.end());

    for(Byte index : this->focusList){
        this->images.removeAt(index - 1);

        if(this->files.count() == this->images.count()){
            this->files.removeAt(index - 1);

        }

        this->focusList.clear();

        this->update();

    }

}

void ImagesManager::clearImages(){
    this->images.clear();
    this->files.clear();

    this->focusList.clear();
    
    this->update();

}

void ImagesManager::insertAtPrevious(){
    QStringList files = QFileDialog::getOpenFileNames(this, QStringLiteral("添加图片"), "./", QStringLiteral("图片文件(*png *jpg *jpeg)"));

    if(files.size() != 0){
        QList<QImage> images = QList<QImage>();

        // 加载图片
        for(QString filepath : files){
            images.push_back(QImage(filepath));

        }

        // 添加图片
        for(int i = 0; i < images.size(); i++){
            this->files.insert(this->focusList.at(0) - 1 + i, files.at(i));
            this->images.insert(this->focusList.at(0) - 1 + i, images.at(i));

        }

        this->focusList.clear();

        this->update();

    }

}

void ImagesManager::insertAtNext(){
    QStringList files = QFileDialog::getOpenFileNames(this, QStringLiteral("添加图片"), "./", QStringLiteral("图片文件(*png *jpg *jpeg)"));

    if(files.size() != 0){
        QList<QImage> images = QList<QImage>();

        // 加载图片
        for(QString filepath : files){
            images.push_back(QImage(filepath));

        }

        // 添加图片
        for(int i = 0; i < images.size(); i++){
            this->files.insert(this->focusList.at(0), files.at(i));
            this->images.insert(this->focusList.at(0), images.at(i));

        }

        this->focusList.clear();

        this->update();

    }

}

// 事件过滤器
bool ImagesManager::eventFilter(QObject* target, QEvent* event){
    if(target == this->parent->viewport()){
        if(event->type() == QEvent::Wheel){
            if(this->showingIndex != 0){
                return true;

            }else{
                return false;

            }

        }

    }

    return false;

}
